/********************************************************************
Crytek Source File.
Copyright (C), Crytek Studios, 2001-2009.
---------------------------------------------------------------------
File name:   AINetworkDebugRenderer.h
$Id$
Description: Helper functions to draw some interesting debug shapes
             over the network.

---------------------------------------------------------------------
History:
- 2009-6-10   : Created by Evgeny Adamenkov

*********************************************************************/

#ifndef _AI_NETWORK_DEBUG_RENDERER_H_
#define _AI_NETWORK_DEBUG_RENDERER_H_

#if _MSC_VER > 1000
#pragma once
#endif


#include "AIAbstractDebugRenderer.h"

#include "INotificationNetwork.h"

#include <vector>


// !!! The same value as in Code/Sandbox/Editor/Console/ConsoleConnection.cpp
enum { DEFAULT_PORT = 9432 };


class CAINetworkDebugRenderer : public CAIAbstractDebugRenderer
{
public:

	CAINetworkDebugRenderer();


	//////////////////////////////////////////////////////////////////////////
	//
	//	IAIDebugRenderer interface methods

	// Fabricated values
	virtual float GetCameraFOV() { return 1.5f; } // radians
	virtual int GetWidth()	{ return 800; }
	virtual int GetHeight()	{ return 600; }

	virtual Vec3 GetCameraPos();
	virtual void DrawAABB(const AABB& aabb, bool bSolid, const ColorB& color, EBoundingBoxDrawStyle bbDrawStyle);
	virtual void DrawAABB(const AABB& aabb, const Matrix34& matWorld, bool bSolid, const ColorB& color, EBoundingBoxDrawStyle bbDrawStyle);
	virtual void DrawArrow(const Vec3& vPos, const Vec3& vLength, float fWidth, const ColorB& color);
	virtual void DrawCapsuleOutline(const Vec3& vPos0, const Vec3& vPos1, float fRadius, const ColorB& color);
	virtual void DrawCircleOutline(const Vec3& vPos, float fRadius, const ColorB& color);
	virtual void DrawCircles(const Vec3& vPos, float fMinRadius, float fMaxRadius, int numRings, const ColorB& insideColor, const ColorB& outsideColor);
	virtual void DrawCone(const Vec3& vPos, const Vec3& vDir, float fRadius, float fHeight, const ColorB& color, bool bDrawShaded = true);
	virtual void DrawCylinder(const Vec3& vPos, const Vec3& vDir, float fRadius, float fHeight, const ColorB& color, bool bDrawShaded = true);
	virtual void DrawEllipseOutline(const Vec3& vPos, float fRadiusX, float fRadiusY, float fOrientation, const ColorB& color);
	virtual void Draw2dImage(float fX, float fY, float fWidth, float fHeight, int nTextureID, float fS0 = 0.f, float fT0 = 0.f, float fS1 = 1.f, float fT1 = 1.f, float fAngle = 0.f, float fR = 1.f, float fG = 1.f, float fB = 1.f, float fA = 1.f, float fZ = 1.f);
	virtual void Draw2dLabel(int nCol, int nRow, const char* szText, const ColorB& color);
	virtual void Draw2dLabel(float fX, float fY, float fFontSize, const ColorB& color, bool bCenter, const char* format, ...) PRINTF_PARAMS(7, 8);
	virtual void Draw3dLabel(const Vec3& vPos, float fFontSize, const char* format, ...) PRINTF_PARAMS(4, 5);
	virtual void Draw3dLabelEx(const Vec3& vPos, float fFontSize, const ColorB& color, bool bFixedSize, bool bCenter, const char* format, ...) PRINTF_PARAMS(7, 8);
	virtual void DrawLine(const Vec3& v0, const ColorB& colorV0, const Vec3& v1, const ColorB& colorV1, float fThickness = 1.f);
	virtual void DrawOBB(const OBB& obb, const Vec3& vPos, bool bSolid, const ColorB& color, EBoundingBoxDrawStyle bbDrawStyle);
	virtual void DrawOBB(const OBB& obb, const Matrix34& matWorld, bool bSolid, const ColorB& color, EBoundingBoxDrawStyle bbDrawStyle);
	virtual void DrawPolyline(const Vec3* va, uint32 nPoints, bool bClosed, const ColorB& color, float fThickness = 1.f);
	virtual void DrawPolyline(const Vec3* va, uint32 nPoints, bool bClosed, const ColorB* colorArray, float fThickness = 1.f);
	virtual void DrawRangeArc(const Vec3& vPos, const Vec3& vDir, float fAngle, float fRadius, float fWidth, const ColorB& colorFill, const ColorB& colorOutline, bool bDrawOutline);
	virtual void DrawRangeBox(const Vec3& vPos, const Vec3& vDir, float fSizeX, float fSizeY, float fWidth, const ColorB& colorFill, const ColorB& colorOutline, bool bDrawOutline);
	virtual void DrawRangeCircle(const Vec3& vPos, float fRadius, float fWidth, const ColorB& colorFill, const ColorB& colorOutline, bool bDrawOutline);
	virtual void DrawRangePolygon(const Vec3* va, uint32 nPoints, float fWidth, const ColorB& colorFill, const ColorB& colorOutline, bool bDrawOutline);
	virtual void DrawSphere(const Vec3& vPos, float fRadius, const ColorB& color, bool bDrawShaded = true);
	virtual void DrawTriangle(const Vec3& v0, const ColorB& colorV0, const Vec3& v1, const ColorB& colorV1, const Vec3& v2, const ColorB& colorV2);
	virtual void DrawTriangles(const Vec3* va, uint32 numPoints, const ColorB& color);
	virtual void DrawWireFOVCone(const Vec3& vPos, const Vec3& vDir, float fRadius, float fFOV, const ColorB& color);
	virtual void DrawWireSphere(const Vec3& vPos, float fRadius, const ColorB& color);
	virtual ITexture* LoadTexture(const char* szNameOfTexture, uint32 nFlags);
	virtual void TextToScreen(float fX, float fY, const char* format, ...) PRINTF_PARAMS(4, 5);
	virtual void TextToScreenColor(int nX, int nY, float fRed, float fGreen, float fBlue, float fAlpha, const char* format, ...) PRINTF_PARAMS(8, 9);
	
	virtual bool ProjectToScreen(float fInX, float fInY, float fInZ, float* pfOutX, float* pfOutY, float* pfOutZ);

	virtual void SetMaterialColor(float fRed, float fGreen, float fBlue, float fAlpha);
	
	virtual void SetFlags(SAuxGeomRenderFlags flags);
	virtual int GetFrameID();
	virtual void DebugDraw() { assert(!!!"Should not be here!"); }
	
	
private:

	//////////////////////////////////////////////////////////////////////////
	//
	//	Sender state machine

	enum ESenderState
	{
		eSS_WAITING_FOR_FRAME_START,
		eSS_COLLECTING_COMMANDS_TO_SEND,
		eSS_IN_DELAY
	};
	
	ESenderState m_eSenderState;

	bool IsSenderReady();
	void SwitchSenderStateTo(ESenderState eSenderNewState);


	//////////////////////////////////////////////////////////////////////////
	//
	//	Serialization helper

	class CDrawCommandsOutputStream
	{
		INotificationNetworkClient* m_pNotificationNetworkClient;
		std::vector<uint8> m_buffer;
		
	public:
		CDrawCommandsOutputStream() : m_pNotificationNetworkClient(NULL) { assert(gEnv->IsDedicated()); }
		
		void Clear() { m_buffer.clear(); }
		
		void Send();
	
		size_t Size() { return m_buffer.size(); }
	
		template <typename T>
		CDrawCommandsOutputStream& operator<<(const T& val)
		{
			typedef typename SerialTypeOf<T>::type SerialType;
			SerialType value = static_cast<SerialType>(val);

#ifdef NEED_ENDIAN_SWAP
			SwapEndian(value);
#endif

			size_t old_size = m_buffer.size();
			m_buffer.resize(old_size + sizeof(value));
			memcpy(&m_buffer[old_size], &value, sizeof(value));
			return *this;
		}
		
		CDrawCommandsOutputStream& operator<<(const char* sz);

		template <typename T>
		void Write(const T* a, size_t size)
		{
#ifdef NEED_ENDIAN_SWAP
			for (size_t i = 0; i < size; ++i)
			{
				*this << a[i];
			}
#else
			typedef typename SerialTypeOf<T>::type SerialType;
			assert(sizeof(T) == sizeof(SerialType));
			size_t old_size = m_buffer.size();
			size_t delta_size = size * sizeof(SerialType);
			m_buffer.resize(old_size + delta_size);
			memcpy(&m_buffer[old_size], a, delta_size);
#endif
		}
		
	};	// class CDrawCommandsOutputStream

	
	CDrawCommandsOutputStream m_outputStream;
	
	int   m_currentFrameID;
	float m_delayStartTime;
};

#endif	// #ifndef _AI_NETWORK_DEBUG_RENDERER_H_
